/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.seari.ats_iscs.handler;

import com.seari.ats_iscs.AtsIscsClient;
import com.seari.ats_iscs.AtsIscsHelper;
import com.seari.bean.ats_iscs.AtsIscsDataBean;
import com.seari.bean.ats_iscs.AtsIscsMessageInstance;
import com.seari.bean.ats_iscs.AtsIscsMessageTypeEnum;
import com.seari.commonutils.common.DataUtils;
import com.seari.utils.DataUtil;
import com.seari.utils.JedisPoolUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.concurrent.ScheduledFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author Rainbow
 */
public class AtsIscsHandler extends SimpleChannelInboundHandler {

    protected static Logger logger = LoggerFactory.getLogger(AtsIscsHandler.class);
    AtsIscsClient client;
    Jedis jedis;
    private ChannelHandlerContext ctx;

    public AtsIscsHandler() {
        super();
    }

    public AtsIscsHandler(AtsIscsClient client) {
        System.out.println("com.seari.ats_iscs.handler.AtsIscsHandler.<init>()>>>>>Jedis pool status:"+JedisPoolUtils.getStatus());
        jedis = JedisPoolUtils.getJedis();
        System.out.println("com.seari.ats_iscs.handler.AtsIscsHandler.<init>()get jedis finished"+jedis.isConnected());
        this.client = client;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        logger.info("ATS_ISCS#########发送订阅报文##########");
        //设置报文头
        ByteBuf buffer = client.channel.alloc().buffer((4 + 2 + 2) * 4);
        buffer.writeBytes(AtsIscsHelper.ATS_ISCS_HEADER);
        //设置报文长度
        buffer.writeBytes(DataUtil.reverse(DataUtils.int16ToByteArray(2)));
        //设置报文类型
        buffer.writeBytes(DataUtil.reverse(DataUtil.short2byte(AtsIscsMessageTypeEnum.INITIAL_SUBSCRIBE.getValue())));
        //发送报文
        client.channel.writeAndFlush(buffer);
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        AtsIscsDataBean dataBean = (AtsIscsDataBean) msg;
        Integer messageType = dataBean.getMessageType();
        byte[] content = dataBean.getContent();
        if (AtsIscsMessageTypeEnum.SUBSCRIPTION_RESPONSE.getValue().equals(messageType)) {
            //订阅应答，身份识别号
            String identityNumber = DataUtil.BytesToHexStr(content);
            logger.info("ATS_ISCS#########服务端发送的身份识别号：'{}'##########",identityNumber);
            String id = DataUtil.BytesToHexStr(content);
            AtsIscsClient.identityNumber = content;
            //创建定时更新订阅的线程
            logger.info("ATS_ISCS#########客户端创建发送更新订阅报文线程##########",identityNumber);
            ScheduledFuture<?> scheduledFuture = ctx.channel().eventLoop().scheduleAtFixedRate(new AtsIscsTimer(client, content, true),
                    20, 20, TimeUnit.SECONDS);
            client.setScheduledFuture(scheduledFuture);
        } else if (AtsIscsMessageTypeEnum.INITIAL_BEGIN_SUBSCRIBE.getValue().equals(messageType)) {
            logger.info("ATS_ISCS#########服务端开始初始化，传输对象##########");
        } else if (AtsIscsMessageTypeEnum.INITIAL_END_SUBSCRIBE.getValue().equals(messageType)) {
            logger.info("ATS_ISCS#########服务端初始化结束##########");
        } else if (AtsIscsMessageTypeEnum.CREATE_OBJECT_SUBSCRIBE.getValue().equals(messageType)) {
            logger.info("ATS_ISCS#########通知对象生成##########");
            AtsIscsMessageInstance instance = new AtsIscsMessageInstance();
            //获取对象组ID，两个字节
            instance.setGroupId((content[1] & 0xff) << 8 | content[0] & 0xff);
            //获取对象ID，四个字节
            instance.setId((content[5] & 0xff) << 24 | (content[4] & 0xff) << 16 | (content[3] & 0xff) << 8 | content[2] & 0xff);
            //迭代获取对象属性，属性ID两个字节，属性值通常四个字节
            getPropertiesMap(content, instance);
            instance.setHexStr(dataBean.getHexStr());

            if (client.getListener() != null) {
                client.getListener().onMessage(instance);
            }
            logger.info("ATS_ISCS#########对象已存储，{}##########",instance.toString());
        } else if (AtsIscsMessageTypeEnum.UPDATE_OBJECT_SUBSCRIBE.getValue().equals(messageType)) {
            logger.info("ATS_ISCS#########对象属性更新##########");
            //通过对象组ID和对象ID获取具体的对象
            AtsIscsMessageInstance instance = new AtsIscsMessageInstance();
            Integer groupId = (content[1] & 0xff) << 8 | content[0] & 0xff;
            Integer id = (content[5] & 0xff) << 24 | (content[4] & 0xff) << 16 | (content[3] & 0xff) << 8 | content[2] & 0xff;
            instance.setGroupId(groupId);
            instance.setId(id);
            if (instance != null) {
                //更改传递的属性值
                getPropertiesMap(content, instance);
                instance.setHexStr(dataBean.getHexStr());
                if (client.getListener() != null) {
                    client.getListener().onMessage(instance);
                }
            }
        } else if (AtsIscsMessageTypeEnum.REMOVE_OBJECT_SUBSCRIBE.getValue().equals(messageType)) {
            logger.info("ATS_ISCS#########销毁对象##########");
            //通过对象组ID和对象ID获取具体的对象
            AtsIscsMessageInstance instance = new AtsIscsMessageInstance();
            Integer groupId = (content[1] & 0xff) << 8 | content[0] & 0xff;
            Integer id = (content[5] & 0xff) << 24 | (content[4] & 0xff) << 16 | (content[3] & 0xff) << 8 | content[2] & 0xff;
            instance.setGroupId(groupId);
            instance.setId(id);
            if (instance != null) {
                //销毁对象
                logger.info("ATS_ISCS#########销毁对象，{}##########",instance.toString());
            }
        } else {
            logger.info("ATS_ISCS#########数据类型错误，messageType:{}##########",messageType);
        }
    }

    /**
     * 从byte[]中获取属性键值对，然后存入实体对象
     *
     * @param content
     * @param instance
     */
    public void getPropertiesMap(byte[] content, AtsIscsMessageInstance instance) {
        boolean flag = false;
        Map<Integer, Integer> properties = instance.getPropertiesMap();
        if(properties == null){
            properties = new HashMap<>();
        }
        List<byte[]> tagList = new ArrayList<>();
        //判断对象组是否为列车
        try {
            if (7 == instance.getGroupId()) {
                flag = true;
            }
            for (int i = 6; i < content.length; ) {
                Integer propertyId = (content[i + 1] & 0xff) << 8 | content[i] & 0xff;
                if (flag) {
                    //判断属性id是否为列车标签
                    if (AtsIscsMessageTypeEnum.CAR_TAG.getValue().equals(propertyId)) {
                        Integer tagLength = content[i + 2] & 0xff;
                        byte[] tag = new byte[tagLength];
                        for (int j = 0; j < tagLength; j++) {
                            tag[j] = content[i + 3 + j];
                        }
                        tagList.add(tag);
                        i += (3 + tagLength);
                        continue;
                    }
//                    else if(AtsIscsMessageTypeEnum.CAR_HEAD.getValue().equals(propertyId)){
//                        Integer propertyValue = (content[i + 3] & 0xff) << 24 | (content[i + 2] & 0xff) << 16 | (content[i + 5] & 0xff) << 8 | content[i + 4] & 0xff;
//                        properties.put(propertyId, propertyValue);
//                        i += 6;
//                        continue;
//                    }
                }
                Integer propertyValue = (content[i + 5] & 0xff) << 24 | (content[i + 4] & 0xff) << 16 | (content[i + 3] & 0xff) << 8 | content[i + 2] & 0xff;
                properties.put(propertyId, propertyValue);
                i += 6;
            }
        }catch (Exception e){
            logger.error("对象{}，异常{}",instance.toString(),e.toString());
        }
        instance.setPropertiesMap(properties);
        instance.setTagList(tagList);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        closeJedis();
    }

    public void closeJedis() {
            System.out.println("close jedis");
            JedisPoolUtils.close(jedis);
    }

    public void setCtx(ChannelHandlerContext ctx){
        this.ctx = ctx;
    }

}
